#ifndef _HAVE_UTIL_H
#define _HAVE_UTIL_H

#include <stdlib.h>
#include <string.h>

#include <curl/curl.h>

#include "error.h"
#include "main.h"

int find_string(const char * string, const char* strings[], int size);
char* string_concat(const char* src[]);
char* string_duplicate(const char* src);

/**
*   设置一些简单的Header。
*/
void curl_common_setup(CURL* curl, const char* portal_host,
    const char* portal_search);

typedef struct {
    char *memory;
    size_t size;
    size_t max_size;
} _CURL_EASY_MEMORY_STRUCT;

__attribute__ ((unused))
static size_t curl_easy_memory_callback(void *contents, size_t size, size_t nmemb, void *userp)
{
    size_t realsize = size * nmemb;
    _CURL_EASY_MEMORY_STRUCT *mem = (_CURL_EASY_MEMORY_STRUCT*)userp;

    if (mem -> size + realsize > mem -> max_size) {
        error(0, 0, "cURL read error: data size exceed, "
            "the max is %zu but now read %zu",
            mem -> max_size, mem -> size + realsize);
        return 0;
    }

    char* ptr = (char*) realloc(mem -> memory, mem -> size + realsize + 1);
    if (!ptr) {
        error(0, 0, "cURL read error: not enough memory");
        return 0;
    }

    mem -> memory = ptr;
    memcpy(&(mem -> memory[mem->size]), contents, realsize);
    mem -> size += realsize;
    mem -> memory[mem -> size] = 0;

    return realsize;
}

/*
    A marco to simply the use of libcurl easy API.
    variables: CURL: the CURL easy handle
               CURLcode: the curl_easy_perform's return code
               chunk.memory: the data read from cURL
               chunk.size: the length of data read from cURL
               status: the HTTP status code
*/
#define CURL_EASY_SETUP(SETUP_ACTION, PERFORM_ACTION, FAILED_ACTION, ADDRESS,  \
BIND_INTERFACE, MAX_READ_SIZE)                                                 \
    if (curl_global_init(CURL_GLOBAL_DEFAULT) != 0) {                          \
        error(0, 0, "libcurl global initializion failed");                     \
        { FAILED_ACTION }                                                      \
    }                                                                          \
    CURL* curl = curl_easy_init();                                             \
    if (curl != NULL) {                                                        \
        _CURL_EASY_MEMORY_STRUCT chunk;                                        \
        chunk.memory = (char*) malloc(1);                                      \
        chunk.memory[0] = 0;                                                   \
        chunk.size = 0;                                                        \
        chunk.max_size = (MAX_READ_SIZE);                                      \
                                                                               \
        curl_easy_setopt(curl, CURLOPT_URL, (ADDRESS));                        \
        curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, "http");                 \
        if (BIND_INTERFACE != NULL) {                                          \
            char* interface_str = (char*) malloc(strlen(BIND_INTERFACE) + 4);  \
            memcpy(interface_str, "if!", 3);                                   \
            strcpy(interface_str + 3, BIND_INTERFACE);                         \
            curl_easy_setopt(curl, CURLOPT_INTERFACE, interface_str);          \
        }                                                                      \
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,                          \
                            curl_easy_memory_callback);                        \
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);             \
        { SETUP_ACTION }                                                       \
                                                                               \
        CURLcode res = curl_easy_perform(curl);                                \
        if(res != CURLE_OK) {                                                  \
            error(0, 0, "curl_easy_perform() failed: %s",                      \
                    curl_easy_strerror(res));                                  \
            { FAILED_ACTION }                                                  \
        }                                                                      \
                                                                               \
        long status;                                                           \
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);              \
                                                                               \
        { PERFORM_ACTION }                                                     \
        curl_easy_cleanup(curl);                                               \
        free(chunk.memory);                                                    \
    } else {                                                                   \
      error(0, 0, "libcurl easy initializion failed");                         \
        { FAILED_ACTION }                                                      \
    }

#endif

void char_to_hex(char code, char* buffer);
int char_is_hex(char c);
int hex_to_char(const char* buffer);
char* url_encode_component(const char* string);
